package com.biz.primus.ms.payment.service;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.*;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.biz.primus.base.exception.BizSilentException;
import com.biz.primus.common.utils.JsonUtils;
import com.biz.primus.common.utils.StringUtil;
import com.biz.primus.common.utils.Timers;
import com.biz.primus.model.payment.vo.req.AliOrderReqVo;
import com.biz.primus.model.payment.vo.req.IAliPaymentReqVo;
import com.biz.primus.model.payment.vo.req.PaymentRefundReqVo;
import com.biz.primus.model.payment.vo.req.PaymentReqVo;
import com.biz.primus.model.payment.vo.resp.CommonPaidRespVo;
import com.biz.primus.model.payment.vo.resp.PaymentRefundRespVo;
import com.biz.primus.ms.base.service.AbstractBaseService;
import com.biz.primus.ms.payment.channel.alipay.IAlipayPayment;
import com.biz.primus.ms.payment.channel.alipay.config.AlipayConfig;
import java.util.HashMap;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

/**
 * Created by defei on 9/27/17.
 */
@Slf4j
@Service
public class AliPaymentService extends AbstractBaseService {


    CommonPaidRespVo isPaid(IAliPaymentReqVo aliPaymentReqVo, String tradeNo, String mchOrderNo) {

        if (StringUtils.isEmpty(tradeNo) && StringUtils.isBlank(mchOrderNo)) {
            throw new BizSilentException("tradeNo and mchOrderNo can not be both null.");
        }
        if (log.isDebugEnabled()) {
            log.debug("tradeNo--> {}", tradeNo);
            log.debug("mchOrderNo--> {}", mchOrderNo);
        }
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.ali_api_gateway, aliPaymentReqVo.getPartner(), aliPaymentReqVo.getPrivateKey(), "json", AlipayConfig.input_charset, AlipayConfig.ali_public_key, "RSA2");
        AlipayTradeQueryRequest alipayTradeQueryRequest = new AlipayTradeQueryRequest();
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        model.setTradeNo(tradeNo);
        model.setOutTradeNo(mchOrderNo);
        alipayTradeQueryRequest.setBizModel(model);
        try {
            AlipayTradeQueryResponse alipayTradeQueryResponse = alipayClient.execute(alipayTradeQueryRequest);
            boolean isPaid = alipayTradeQueryResponse.isSuccess() && (StringUtils.equals(IAlipayPayment.TradeStatus.TRADE_SUCCESS,
                    alipayTradeQueryResponse.getTradeStatus()) || StringUtils.equals(IAlipayPayment.TradeStatus.TRADE_FINISHED, alipayTradeQueryResponse.getTradeStatus()));
            return new CommonPaidRespVo(alipayTradeQueryResponse.getTradeNo(), isPaid, alipayTradeQueryResponse.getBuyerUserId());
        } catch (AlipayApiException e) {
            log.error("查询支付宝支付状态失败", e);
        }
        throw new BizSilentException("查询支付宝单笔交易失败");
    }

    String createMobilePayment(PaymentReqVo paymentReqVo, IAliPaymentReqVo aliPaymentReqVo) {

        Timers timers = Timers.createAndBegin(log.isDebugEnabled());
        String params;
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.ali_api_gateway, aliPaymentReqVo.getPartner(), aliPaymentReqVo.getPrivateKey(), "json", AlipayConfig.input_charset, AlipayConfig.ali_public_key, "RSA2");
        AlipayTradeAppPayRequest alipayTradeAppPayRequest = new AlipayTradeAppPayRequest();
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setBody(paymentReqVo.getBody());
        model.setSubject(paymentReqVo.getSubject());
        model.setOutTradeNo(paymentReqVo.getMchOrderNo());
        model.setTimeoutExpress("30m");
        model.setTotalAmount(StringUtil.formatPriceToYuanWithFen(paymentReqVo.getPayAmount()));
        model.setPassbackParams(paymentReqVo.getMchId().toString());
        alipayTradeAppPayRequest.setBizModel(model);
        alipayTradeAppPayRequest.setNotifyUrl(aliPaymentReqVo.getNotifyUrl());
        try {
            AlipayTradeAppPayResponse execute = alipayClient.sdkExecute(alipayTradeAppPayRequest);
            params = execute.getBody();
        } catch (AlipayApiException e) {
            if (log.isDebugEnabled()) {
                log.error("get alipay mobile pay request failed", e);
            }
            throw new BizSilentException("签名失败，无法发起支付");
        }
        timers.record("计算签名");
        timers.print("use time alipay-sign");
        return params;
    }

    String createPcPayment(PaymentReqVo paymentReqVo, AliOrderReqVo aliPaymentReqVo) {

        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.ali_api_gateway, aliPaymentReqVo.getPartner(), aliPaymentReqVo.getPrivateKey(), "json", AlipayConfig.input_charset, AlipayConfig.ali_public_key, "RSA2");
        Timers timers = Timers.createAndBegin(log.isDebugEnabled());
        String params;
        try {
            AlipayTradePagePayRequest alipayTradePagePayRequest = new AlipayTradePagePayRequest();
            AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
            model.setBody(paymentReqVo.getBody());
            model.setSubject(paymentReqVo.getSubject());
            model.setOutTradeNo(paymentReqVo.getMchOrderNo());
            model.setTimeoutExpress("30m");
            model.setTotalAmount(StringUtil.formatPriceToYuanWithFen(paymentReqVo.getPayAmount()));
            model.setPassbackParams(paymentReqVo.getMchId().toString());
            alipayTradePagePayRequest.setBizModel(model);
            alipayTradePagePayRequest.setNotifyUrl(aliPaymentReqVo.getNotifyUrl());
            alipayTradePagePayRequest.setReturnUrl(aliPaymentReqVo.getReturnUrl());
            params = alipayClient.pageExecute(alipayTradePagePayRequest).getBody();
        } catch (Throwable e) {
            if (log.isDebugEnabled()) {
                log.error("get alipay mobile pay request params sign failed", e);
            }
            throw new BizSilentException("签名失败，无法发起支付");
        }
        timers.record("计算签名");
        timers.print("use time alipay-sign");
        return params;
    }

    String createWapPayment(PaymentReqVo paymentReqVo, AliOrderReqVo aliPaymentReqVo) {

        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.ali_api_gateway, aliPaymentReqVo.getPartner(), aliPaymentReqVo.getPrivateKey(), "json", AlipayConfig.input_charset, AlipayConfig.ali_public_key, "RSA2");
        Timers timers = Timers.createAndBegin(log.isDebugEnabled());
        String params;
        try {
            AlipayTradeWapPayRequest alipayTradeWapPayRequest = new AlipayTradeWapPayRequest();
            AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
            model.setBody(paymentReqVo.getBody());
            model.setSubject(paymentReqVo.getSubject());
            model.setOutTradeNo(paymentReqVo.getMchOrderNo());
            model.setTimeoutExpress("30m");
            model.setTotalAmount(StringUtil.formatPriceToYuanWithFen(paymentReqVo.getPayAmount()));
            model.setPassbackParams(paymentReqVo.getMchId().toString());
            alipayTradeWapPayRequest.setBizModel(model);
            alipayTradeWapPayRequest.setNotifyUrl(aliPaymentReqVo.getNotifyUrl());
            alipayTradeWapPayRequest.setReturnUrl(aliPaymentReqVo.getReturnUrl());
            params = alipayClient.execute(alipayTradeWapPayRequest).getBody();
        } catch (Throwable e) {
            if (log.isDebugEnabled()) {
                log.error("get alipay mobile pay request params sign failed", e);
            }
            throw new BizSilentException("签名失败，无法发起支付");
        }
        timers.record("计算签名");
        timers.print("use time alipay-sign");
        return params;
    }

    /**
     * 退款
     */
    PaymentRefundRespVo refund(PaymentRefundReqVo paymentRefundReqVo, AliOrderReqVo aliPaymentReqVo) {

        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.ali_api_gateway, aliPaymentReqVo.getPartner(), aliPaymentReqVo.getPrivateKey(), "json", AlipayConfig.input_charset, AlipayConfig.ali_public_key, "RSA2");
        Timers timers = Timers.createAndBegin(log.isDebugEnabled());
        AlipayTradeRefundResponse result;
        try {
            AlipayTradeRefundRequest alipayTradeRefundRequest = new AlipayTradeRefundRequest();
            AlipayTradeRefundModel model = new AlipayTradeRefundModel();
            model.setOutTradeNo(paymentRefundReqVo.getMchOrderNo());
            model.setOutRequestNo(paymentRefundReqVo.getRefundNo());
            model.setRefundAmount(StringUtil.formatPriceToYuanWithFen(paymentRefundReqVo.getRefundAmount()));
            model.setRefundReason(paymentRefundReqVo.getRefundReason());
            alipayTradeRefundRequest.setNotifyUrl(aliPaymentReqVo.getRefundNotifyUrl());
            alipayTradeRefundRequest.setBizModel(model);
            result = alipayClient.execute(alipayTradeRefundRequest);
            log.debug("Alipay return: {} for refund:{}", result.getBody(), paymentRefundReqVo);
        } catch (Exception e) {
            if (log.isDebugEnabled()) {
                log.error("Got an exception from alipay refund.", e);
            }
            throw new BizSilentException("退款失败");
        }
        timers.record("发起退款");
        timers.print("use time alipay refund");
        PaymentRefundRespVo paymentRefundRespVo = new PaymentRefundRespVo();
        paymentRefundRespVo.setRefundSuccess(result.isSuccess());
        return paymentRefundRespVo;
    }

    /**
     * 退款查询
     */
    PaymentRefundRespVo refundQuery(PaymentRefundReqVo paymentRefundReqVo, AliOrderReqVo aliPaymentReqVo) {

        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.ali_api_gateway, aliPaymentReqVo.getPartner(), aliPaymentReqVo.getPrivateKey(), "json", AlipayConfig.input_charset, AlipayConfig.ali_public_key, "RSA2");
        Timers timers = Timers.createAndBegin(log.isDebugEnabled());
        AlipayTradeFastpayRefundQueryResponse result;
        try {
            AlipayTradeFastpayRefundQueryRequest alipayTradeFastpayRefundQueryRequest = new AlipayTradeFastpayRefundQueryRequest();
            AlipayTradeRefundModel model = new AlipayTradeRefundModel();
            model.setOutTradeNo(paymentRefundReqVo.getMchOrderNo());
            model.setOutRequestNo(paymentRefundReqVo.getRefundNo());
            model.setRefundAmount(StringUtil.formatPriceToYuanWithFen(paymentRefundReqVo.getRefundAmount()));
            model.setRefundReason(paymentRefundReqVo.getRefundReason());
            alipayTradeFastpayRefundQueryRequest.setNotifyUrl(aliPaymentReqVo.getRefundNotifyUrl());
            alipayTradeFastpayRefundQueryRequest.setBizModel(model);
            result = alipayClient.execute(alipayTradeFastpayRefundQueryRequest);
            log.debug("Alipay return: {} for refund:{}", result.getBody(), paymentRefundReqVo);
        } catch (Exception e) {
            if (log.isDebugEnabled()) {
                log.error("Got an exception from alipay refund.", e);
            }
            throw new BizSilentException("退款失败");
        }
        timers.record("发起退款");
        timers.print("use time alipay refund");
        PaymentRefundRespVo paymentRefundRespVo = new PaymentRefundRespVo();
        paymentRefundRespVo.setRefundSuccess(result.isSuccess());
        return paymentRefundRespVo;
    }

    /**
     * 校验签名 切记alipaypublickey是支付宝的公钥，请去open.alipay.com对应应用下查看。
     */
    Boolean isValidNotify(HashMap<String, String> notifyParams, String publicKey) {
        try {
            return AlipaySignature.rsaCheckV1(notifyParams, publicKey, AlipayConfig.input_charset, AlipayConfig.sign_type);
        } catch (AlipayApiException e) {
            throw new BizSilentException("签名检查失败");
        }
    }

    public HashMap<String, String> parsePayNotifyRespVo(String notifyData) {

        return JsonUtils.json2Obj(notifyData, HashMap.class, String.class, String.class);
    }
}
